package com.hmall.search.service.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.api.dto.ItemDTO;
import com.hmall.api.dto.OrderDetailDTO;
import com.hmall.common.domain.PageDTO;
import com.hmall.common.exception.BizIllegalException;
import com.hmall.common.utils.BeanUtils;
import com.hmall.search.domain.po.Item;
import com.hmall.search.domain.po.ItemDOC;
import com.hmall.search.domain.query.ItemPageQuery;
import com.hmall.search.mapper.ItemMapper;
import com.hmall.search.service.IItemService;
import lombok.RequiredArgsConstructor;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.lucene.search.function.CombineFunction;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 商品表 服务实现类
 * </p>
 *
 * @author 虎哥
 */
@Service
@RequiredArgsConstructor
public class ItemServiceImpl extends ServiceImpl<ItemMapper, Item> implements IItemService {

    private final RestHighLevelClient restHighLevelClient;

    @Override
    public PageDTO<ItemDTO> search(ItemPageQuery query) {
        //构造查询条件
        SearchRequest request = new SearchRequest("items");
        SearchSourceBuilder source = request.source();
        //复杂查询用bool
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //关键词
        if (StrUtil.isNotBlank(query.getKey())) {
            boolQuery.must(QueryBuilders.matchQuery("name", query.getKey()));
        }
        //品牌
        if (StrUtil.isNotBlank(query.getBrand())) {
            boolQuery.filter(QueryBuilders.termQuery("brand", query.getBrand()));
        }
        //分类
        if (StrUtil.isNotBlank(query.getCategory())) {
            boolQuery.filter(QueryBuilders.termQuery("category", query.getCategory()));
        }
        //不需要指定状态,应为能存到es里面的肯定能卖
        //范围
        if (query.getMinPrice() != null) {
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(query.getMinPrice()));
        }
        if (query.getMaxPrice() != null) {
            boolQuery.filter(QueryBuilders.rangeQuery("price").lte(query.getMaxPrice()));
        }

        //添加是否为广告位逻辑
        FunctionScoreQueryBuilder.FilterFunctionBuilder[] functions = {
                new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                        QueryBuilders.termQuery("isAD", true),
                        ScoreFunctionBuilders.weightFactorFunction(1000f)
                )
        };

        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders
                .functionScoreQuery(boolQuery, functions)
                .boostMode(CombineFunction.MULTIPLY);


        //分页
        if (query.getPageNo() != null && query.getPageSize() != null) {
            request.source()
                    .from((query.getPageNo() - 1) * query.getPageSize())
                    .size(query.getPageSize());
        }
        //排序
        if (StrUtil.isNotBlank(query.getSortBy()) && query.getIsAsc() != null) {
            request.source().sort(query.getSortBy(), query.getIsAsc() ? SortOrder.ASC : SortOrder.DESC);
        } else {
            request.source().sort("update_time", SortOrder.DESC);
        }
        request.source().sort("_score", SortOrder.DESC);

        //拼接条件
        request.source().query(functionScoreQueryBuilder);


        SearchResponse response = null;
        //发送查询
        try {
            response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("发送es商品索引库查询失败,参数为" + query, e);
            throw new RuntimeException(e);
        }

        if (response == null) {
            return null;
        }
        SearchHits hits = response.getHits();
        long value = hits.getTotalHits().value;
        SearchHit[] searchHits = hits.getHits();

        List<ItemDTO> collect = Collections.EMPTY_LIST;
        if (searchHits != null) {
            collect = Arrays.stream(searchHits).map(searchHit -> {
                String jsonStr = searchHit.getSourceAsString();
                ItemDOC itemDOC = JSONUtil.toBean(jsonStr, ItemDOC.class);
                ItemDTO itemDTO = BeanUtil.copyProperties(itemDOC, ItemDTO.class);
                return itemDTO;
            }).collect(Collectors.toList());
        }

        //创建返回对象
        PageDTO<ItemDTO> itemDTOPageDTO = new PageDTO<>();
        itemDTOPageDTO.setList(collect);
        itemDTOPageDTO.setTotal(value);
        itemDTOPageDTO.setPages(Long.valueOf(query.getPageNo()));


        return itemDTOPageDTO;
    }

    @Override
    public Map filters() {

        SearchRequest searchRequest = new SearchRequest("items");

        searchRequest.source()
                .aggregation(AggregationBuilders.terms("category_terms").field("category").size(10))
                .aggregation(AggregationBuilders.terms("brand_terms").field("brand").size(10))
                .size(0);

        SearchResponse search = null;
        try {
            search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("查询过滤类型失败");
            throw new RuntimeException(e);
        }

        //解析
        Aggregations aggregations = search.getAggregations();

        if (aggregations == null) {
            return null;
        }

        Terms categoryTerms = aggregations.get("category_terms");
        Terms brandTerms = aggregations.get("brand_terms");

        //保存数组
        ArrayList<String> cateList = new ArrayList<>();
        ArrayList<String> brandList = new ArrayList<>();


        if (categoryTerms != null) {
            List<? extends Terms.Bucket> buckets = categoryTerms.getBuckets();
            for (Terms.Bucket bucket : buckets) {
                String key = bucket.getKeyAsString();
                cateList.add(key);
            }
        }
        if (brandTerms != null) {
            List<? extends Terms.Bucket> buckets = brandTerms.getBuckets();
            for (Terms.Bucket bucket : buckets) {
                String key = bucket.getKeyAsString();
                brandList.add(key);
            }
        }

        HashMap<String, ArrayList<String>> map = new HashMap<>();
        map.put("category", cateList);
        map.put("brand", brandList);

        return map;
    }
}
